package com.huhu.myharmony.ble.controller;


import com.huhu.myharmony.ble.ProtocolEntity;
import com.huhu.myharmony.utils.DataUtils;
import ohos.app.Context;
import ohos.bluetooth.ProfileBase;
import ohos.bluetooth.ble.*;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.UUID;


public class BleHelper {
    private Context context;
    protected static final HiLogLabel loglabel = new HiLogLabel(HiLog.LOG_APP, 0x11111, "BleHelper");
    // 获取中心设备管理对象
    private BleCentralManager centralManager;
    private BlePeripheralDevice peripheralDevice = null;
    private GattCharacteristic writeCharacteristic;
    private static final String SERVICE_UUID = "0000FFB0-0000-1000-8000-00805F9B34FB";
    private static final String NOTIFY_CHARACTER_UUID = "0000FFB2-0000-1000-8000-00805F9B34FB";
    private static final String WRITE_CHARACTER_UUID = "0000FFB1-0000-1000-8000-00805F9B34FB";
    private static final int CUT_LENGTH = 7;
    public boolean isConnected = false;
    private ProtocolEntity protocolEntity = new ProtocolEntity();

    /**
     * 消息类型 ：
     * 0x00:APP下发
     * 0x01:APP获取
     * 0x02:设备上报
     * 0x03:设备请求
     */
    public static final String TYPE_ISSUED = "00";
    public static final String TYPE_OBTAIN = "01";
    public static final String TYPE_REPORT = "02";

    private BleHelper() {
    }

    public void init(Context app) {
        if (context == null && app != null) {
            context = app;
        }
    }


    /**
     * 扫描设备
     *
     * @param filters 设备过滤器
     * @since 2021-10-09
     */
    public void startScan(List<BleScanFilter> filters) {
        centralManager = new BleCentralManager(context, new MyBleCentralManagerCallback());
        centralManager.startScan(filters);
    }

    /**
     * 扫描设备回调
     *
     * @since 2021-10-09
     */
    private class MyBleCentralManagerCallback implements BleCentralManagerCallback {
        // 扫描结果的回调
        @Override
        public void scanResultEvent(BleScanResult bleScanResult) {
            // 根据扫描结果获取外围设备实例
            if (mBleManagerCallback != null) {
                mBleManagerCallback.scanResultCallback(bleScanResult);
            }
//            if (peripheralDevice == null) {
            HiLog.debug(loglabel, "扫描结果回调 scanResultEvent()  DeviceName:" + bleScanResult.getPeripheralDevice().getDeviceName());
            // 获取广播数据中的服务uuids
            List<UUID> uuids = bleScanResult.getServiceUuids();
            for (UUID uuid : uuids) {
                if (SERVICE_UUID.equals(uuid.toString())) {
                    peripheralDevice = bleScanResult.getPeripheralDevice();
                    int length = peripheralDevice.toString().length();
                    String deviceId = peripheralDevice.toString().substring(length - CUT_LENGTH, length);
                    stopScan();
                    bleConnect();
                }
            }
        }

        // 扫描失败回调
        @Override
        public void scanFailedEvent(int event) {
            HiLog.debug(loglabel, "扫描失败 scanFailedEvent()");
        }

        // 组扫描成功回调
        @Override
        public void groupScanResultsEvent(List<BleScanResult> list) {
            // 使用组扫描时在此对扫描结果进行处理
        }
    }

    public void stopScan() {
        // 停止扫描
        if (centralManager != null) {
            centralManager.stopScan();
            centralManager = null;
        }
    }

    public void disconnect() {
        // 停止扫描
        if (peripheralDevice != null) {
            writeCharacteristic.setValue("Disconnect".getBytes(StandardCharsets.UTF_8));
            peripheralDevice.writeCharacteristic(writeCharacteristic);
            // 断开连接
            peripheralDevice.disconnect();
            peripheralDevice = null;
        }
    }

    public void onDestroy() {
        disconnect();
        unRegisterBleManagerCallback();
    }

    /**
     * 主动去获取所Tag设备数据，通过Write(消息类型0x01), Notify接收数据
     */
    public void readInitiativeByTags(List<String> tagIds) {
        String hex = getTagsCommandHexStr(tagIds);
        bleManagerWrite(hex);
    }

    /**
     * 写Tag设备数据，通过Write(消息类型0x01), Notify接收数据
     */
    public void writeBleByTag(String tagId, String value) {
        String hex = getTagCommandHexStr(tagId, Integer.parseInt(value));
        bleManagerWrite(hex);
    }

    private void bleManagerWrite(String hex) {
        if (peripheralDevice == null) {
            return;
        }
        writeCharacteristic.setValue(DataUtils.toByteArray(hex, " "));
        peripheralDevice.writeCharacteristic(writeCharacteristic);
    }

    /**
     * 获取所有Tag数据的指令
     *
     * @param tagId  0001
     */
    public static final String PROTOCOL_ID = "A55A"; // 串口协议标识
    public static final String PROTOCOL_VERSION = "01"; // 串口协议版本

    public String getTagsCommandHexStr(List<String> tagIds) {
        try {
            StringBuilder sb = new StringBuilder();
            String byte1 = PROTOCOL_ID; // 串口协议标识
            String byte2 = PROTOCOL_VERSION;
            String byte3 = TYPE_OBTAIN;
            int dataLen = 8 * tagIds.size();
            String byte4 = DataUtils.encodeHex(dataLen, 4);

            String byteTagLen = DataUtils.encodeHex(4, 4);
            String byteTagValue = "00000000";
            StringBuilder sbTag = new StringBuilder();
            for (String it : tagIds) {
                sbTag.append(it).append(byteTagLen).append(byteTagValue);
            }

            sb.append(byte1).append(byte2).append(byte3).append(byte4).append(sbTag);
            String hexStrSum = DataUtils.makeChecksum(sb.toString());
            int protocolVerify = DataUtils.decodeHEX(hexStrSum) % 256;
            String byteLast = DataUtils.encodeHex(protocolVerify);
            sb.append(byteLast);
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    public String getTagCommandHexStr(String tagId, int value) {
        try {
            StringBuilder sb = new StringBuilder();
            String byte1 = PROTOCOL_ID; // 串口协议标识
            String byte2 = PROTOCOL_VERSION;
            String byte3 = TYPE_ISSUED;
            int dataLen = 8;
            String byte4 = DataUtils.encodeHex(dataLen, 4);

            String byteTagId = tagId;
            String byteTagLen = DataUtils.encodeHex(4, 4);
            String byteTagValue = DataUtils.encodeHex(value, 8);

            sb.append(byte1).append(byte2).append(byte3).append(byte4).append(byteTagId).append(byteTagLen).append(byteTagValue);

            String hexStrSum = DataUtils.makeChecksum(sb.toString());
            int protocolVerify = DataUtils.decodeHEX(hexStrSum) % 256;
            String byteLast = DataUtils.encodeHex(protocolVerify);
            sb.append(byteLast);
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }


    public void bleConnect() {
        HiLog.debug(loglabel, "开始连接蓝牙connect()  DeviceName:" + peripheralDevice.getDeviceName());
        // 连接到BLE外围设备
        peripheralDevice.connect(false, new BlePeripheralCallback() {
            // 在外围设备上发现服务的回调
            @Override
            public void servicesDiscoveredEvent(int status) {
                super.servicesDiscoveredEvent(status);
                if (status == BlePeripheralDevice.OPERATION_SUCC) {
                    HiLog.debug(loglabel, "发现服务成功 servicesDiscoveredEvent()");
                    for (GattService service : peripheralDevice.getServices()) {
                        checkGattCharacteristic(service);
                    }
                    if (mBleManagerCallback != null) {
                        mBleManagerCallback.connectCallback(ProfileBase.STATE_CONNECTED, peripheralDevice.getDeviceName().get());
                    }
                }
            }

            private void checkGattCharacteristic(GattService service) {
                for (GattCharacteristic tmpChara : service.getCharacteristics()) {
                    if (tmpChara.getUuid().equals(UUID.fromString(NOTIFY_CHARACTER_UUID))) {
                        // 启用特征通知
                        peripheralDevice.setNotifyCharacteristic(tmpChara, true);
                    }
                    if (tmpChara.getUuid().equals(UUID.fromString(WRITE_CHARACTER_UUID))) {
                        // 获取GattCharacteristic
                        writeCharacteristic = tmpChara;
                    }
                }
            }

            // 连接状态变更的回调
            @Override
            public void connectionStateChangeEvent(int connectionState) {
                super.connectionStateChangeEvent(connectionState);
                if (connectionState == ProfileBase.STATE_CONNECTED && !isConnected) {
                    HiLog.debug(loglabel, "连接成功 connectionStateChangeEvent() connectionState：" + connectionState);
                    isConnected = true;
                    // 连接成功在外围设备上发现GATT服务，部分手机发现服务失败，需要延迟调用discoverServices()
                    peripheralDevice.discoverServices();
                } else if (connectionState == ProfileBase.STATE_DISCONNECTED) {
                    HiLog.debug(loglabel, "断开连接 connectionStateChangeEvent() connectionState：" + connectionState);
                    isConnected = false;
                    if (mBleManagerCallback != null) {
                        mBleManagerCallback.connectCallback(ProfileBase.STATE_DISCONNECTED, "");
                    }
                }
            }

            // 特征变更的回调
            @Override
            public void characteristicChangedEvent(GattCharacteristic characteristic) {
                super.characteristicChangedEvent(characteristic);
                byte[] value = characteristic.getValue();
                if (value == null) return;
                String toHexStr = DataUtils.toHex(value);
                boolean isVerify = BleHelper.verifyProtocol(toHexStr);//校验
                if (isVerify) {
                    if (protocolEntity == null) {
                        protocolEntity = new ProtocolEntity();
                    }
                    protocolEntity.parseCharacteristic(toHexStr);
                    if (mBleManagerCallback != null) {
                        mBleManagerCallback.characteristicChangedCallback(protocolEntity, toHexStr);
                    }
                }

            }

            @Override
            public void characteristicWriteEvent(GattCharacteristic characteristic, int ret) {
                super.characteristicWriteEvent(characteristic, ret);
                byte[] value = characteristic.getValue();
                if (value == null) return;
                String toHexStr = DataUtils.toHex(value);
                if (mBleManagerCallback != null) {
                    mBleManagerCallback.characteristicWriteCallback(toHexStr);
                }
                boolean isVerify = BleHelper.verifyProtocol(toHexStr);//校验
                if (isVerify) {
                    if (protocolEntity == null) {
                        protocolEntity = new ProtocolEntity();
                    }
                    protocolEntity.parseCharacteristic(toHexStr);
                    if (mBleManagerCallback != null) {
                        mBleManagerCallback.characteristicChangedCallback(protocolEntity, toHexStr);
                    }
                }
            }
        });
    }

    public ProtocolEntity getProtocolEntity() {
        return protocolEntity;
    }

    private static class SingletonHolder {
        private static final BleHelper INSTANCE = new BleHelper();

    }

    public static BleHelper getInstance() {
        return SingletonHolder.INSTANCE;
    }

    /**
     * 协议校验 （从协议标识首节至协议内容尾字节求累加和后再对 256 取余）
     *
     * @param hexStr 带空格的 A5 5A 01 00 00 08 00 02 00 04 00 00 00 8C
     */
    public static boolean verifyProtocol(String hexStr) {
        if (hexStr.isEmpty()) return false;
        String checkHex = hexStr.substring(0, hexStr.lastIndexOf(" "));
        String lastHex = hexStr.substring(hexStr.lastIndexOf(" ") + 1);
        String hexStrSum = DataUtils.makeChecksum(checkHex);
        return DataUtils.decodeHEX(hexStrSum) % 256 == DataUtils.decodeHEX(lastHex);
    }

    private BleManagerCallback mBleManagerCallback;

    public void registerBleManagerCallback(BleManagerCallback bleManagerCallback) {
        this.mBleManagerCallback = bleManagerCallback;
    }

    public void unRegisterBleManagerCallback() {
        mBleManagerCallback = null;
    }

    public interface BleManagerCallback {
        void scanResultCallback(BleScanResult var1);

        void connectCallback(int var1, String deviceName);

        void characteristicChangedCallback(ProtocolEntity protocolEntity, String hexStr);

        void characteristicWriteCallback(String hexStr);
    }
}
